package com.fit.utils.se;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 树工具类
 * @author hcl
 * @since 2020/5/15
 */
public class TreeUtil {



    /**
     * 树组装工具
     * @author hcl
     * @param list 数据
     * @param idGetFun 获取id的fun
     * @param pidGetFun 获取pid的fun
     * @param subSetConsumer 设置sub子节点的消费者
     * @param rootPidVal root节点pid的值
     * @return java.util.List<T>
     * @since 2020/5/15
     */
    public static <T,V> List<T> assemblyTree(List<T> list,
                                             Function<T,V> idGetFun,
                                             Function<T,V> pidGetFun,
                                             BiConsumer<T,List<T>> subSetConsumer,
                                             V rootPidVal){
        //根据pid分组
        Map<V,List<T>> pidMap = list
                .parallelStream()
                .collect(Collectors.groupingBy(pidGetFun));
        //获取root节点
        List<T> rootNode = pidMap.get(rootPidVal);
        if(rootNode == null || rootNode.size() == 0){
            return Collections.emptyList();
        }
        //根据root节点递归获取子节点
        rootNode
                .parallelStream()
                .forEach(e->recursiveAssemblyTree(e, pidMap, idGetFun, subSetConsumer));
        return rootNode;
    }

    /** 
     * 递归组装子节点
     * @author hcl 
     * @param pNode 父节点
     * @param pidMap 根据pid分组后的map
     * @param idGetFun 获取id的fun
     * @param subSetConsumer 设置sub子节点的消费者
     * @since 2020/5/15
     */
    private static <T,V> void recursiveAssemblyTree(T pNode,
                                             Map<V,List<T>> pidMap,
                                             Function<T,V> idGetFun,
                                             BiConsumer<T,List<T>> subSetConsumer){
        List<T> childNodes = pidMap.get(idGetFun.apply(pNode));
        subSetConsumer.accept(pNode,childNodes);
        if(childNodes == null || childNodes.size() == 0){
            return ;
        }
        childNodes
                .parallelStream()
                .forEach(e->recursiveAssemblyTree(e, pidMap, idGetFun, subSetConsumer));
    }

}
